#include "genomedatauploader.h"

GenomeDataUploader::GenomeDataUploader(QString gf, QString ff, QObject *parent) :
    QObject(parent)
{
    gffFile.append(gf);
    fastaFile.append(ff);
}


void GenomeDataUploader::process()
{
    qDebug() << "I am in a data uploader thread " << endl;

    //FIRST read fasta and get gene clusters
    //  Cluster output put into programFiles directory
    QString outputClusterFile =  QApplication::applicationDirPath().append("/programFiles/dataFiles/cdHitOut");//QApplication::applicationDirPath().append( "/programFiles/cdHitOut" );//QDir::currentPath().append("/cdHitOut");   //"C:\\Documents and Settings\\jaurisa\\My Documents\\Development\\sagevis\\sageVis-restructured\\SageVis\\data\\contigs\\cdHitOut2";
    readFastaOutputCdHitCluster( fastaFile, outputClusterFile );

    emit(trackProgress(30));

    //THEN read gff file to create datasets
    //      Reformatted file put in programFiles directory
    QString inputClusterFile = outputClusterFile.append(".clstr");

    //old approach- put file with similar name in same directory as gff
    //QString temp = gffFile;
    //QString outputReformattedFile = temp.remove("gff2").append("sageVisReformatted.tab");

    //new approach: put into programFiles directory, with generic name
    //      will write approach to 'saving' project files later
    QString outputReformattedFile = QApplication::applicationDirPath().append("/programFiles/dataFiles/reformattedData");//QApplication::applicationDirPath().append( "/programFiles/reformattedData" );//temp.remove("gff2").append("sageVisReformatted.tab");
    emit( createdReformattedFileSignal( outputReformattedFile) );
    readClusterAndGFFWriteTabDelim(inputClusterFile, gffFile, outputReformattedFile);

    qDebug() << "done in thread" << endl;

    cleanup();

    emit( trackProgress(100) );
    emit finished();
}

void GenomeDataUploader::cleanup()
{
    QDir dir;
    dir.remove(QApplication::applicationDirPath().append( "/programFiles/dataFiles/cdHitOut" ));
    dir.remove(QApplication::applicationDirPath().append( "/programFiles/dataFiles/cdHitOut.clstr" ));
    dir.remove(QApplication::applicationDirPath().append( "/programFiles/dataFiles/cdHitOut.bak.clstr" ));
}


bool GenomeDataUploader::readFastaOutputCdHitCluster(QString inputFastaFile, QString outputClusterFile )
{
    qDebug() << "testing QProcess " << endl;
    QString program = QApplication::applicationDirPath().append("/programFiles/programs/cd-hit-win/cd_hit");//"C:\\Documents and Settings\\jaurisa\\My Documents\\Development\\sagevis\\sageVis-restructured\\SageVis\\programs\\cd-hit-win\\cd_hit";
    QStringList arguments;
    arguments << "-i" << inputFastaFile << "-o" << outputClusterFile <<
                 "-c" << ".9" << "-n" << "5" << "-d" << "1000";

    cdHit = new QProcess(this);
    cdHit->setProcessChannelMode(QProcess::MergedChannels);
    cdHit->start(program, arguments);
    qDebug() << "cdhit started " << endl;

    emit( trackProgress(10) );

    // Wait for it to start
    if(!cdHit->waitForStarted())
    {
        qDebug() << "not waiting for started " << endl;
        return false; //note - not handling false return right now...
    }

    // Continue reading the data until EOF reached
    QByteArray data;

    emit( trackProgress(15) );

    while(cdHit->waitForReadyRead())
    {
        data.append(cdHit->readAll());
        qDebug() << "cdhit running " << endl;
    }

    // Output the data
    qDebug(data.data());
    qDebug("Done!");

    if( cdHit->error() )
        return false;

    return cdHit->exitStatus() == QProcess::NormalExit;
}

bool GenomeDataUploader::readClusterAndGFFWriteTabDelim(QString clusterInputFile, QString gffInputFile, QString outputTabDelimFile)
{

    //note- later can launch cd_hit on faa file to create cluster file.  In this case, don't use clusterInputFile
    //but then can't expect to get all the annotations i am currently assuming ... =/

    QHash<QString, QString> geneIdToClusterHT; // this will store the cluster id for all the genes

    //fill gene id to cluster ht
    QFile cluster( clusterInputFile );
    if( !cluster.exists() )
    {
        qDebug() << "cluster file not found." << endl;
        return false;
    }
    if( ! cluster.open(QIODevice::ReadOnly))
    {
        qDebug() << "file " << clusterInputFile << " can't be opened." << endl;
        return false;
    }
    qDebug() << "file " << gffInputFile << " opened." << endl;

    emit( trackProgress( 35 ) );

    QTextStream clusterStream(&cluster);

    QString clusterId = ".";
    QString geneId;
    QString line;
    do {
        line = clusterStream.readLine(); //read each line
        //qDebug() << "line = " << line << endl;

        if( line.contains("Cluster") ) //grab cluster ids
        {
            clusterId = line.remove(">").remove(" ");

            //qDebug() << "cluster id = " << clusterId << endl;
        }
        else //grab gene id
        {
            QRegExp rx(">.*.pep");//grabs the >geneId.pep
            int pos = rx.indexIn( line );
            QStringList list = rx.capturedTexts();
            for(int i = 0; i < list.size(); i++)
            {
                geneId = list[i].remove(".pep").remove(">");//can also in case remove .cdna  or .cds or what have you
                //qDebug() << "------ geneId    " << geneId << "   ----  cluster id     " << clusterId << endl;

                geneIdToClusterHT.insert(geneId, clusterId); //inster in hashtable
            }
        }
    }while( !clusterStream.atEnd());

    emit( trackProgress(60) );

    cluster.close();

    //now read gff2 file and output the reformated file

    QFile gff2(gffInputFile);

    QFile out( outputTabDelimFile );

    if( !gff2.exists() )
    {
        qDebug() << "file not found." << endl;
        return false;
    }

    if( ! gff2.open(QIODevice::ReadOnly))
    {
        qDebug() << "file " << gffInputFile << " can't be opened." << endl;
        return false;
    }

    if( ! out.open( QIODevice::WriteOnly) )//
    {
        qDebug() << "failed to open output file " << endl;
        return false;
    }

    qDebug() << "file " << gffInputFile << " opened." << endl;

    //this is for csv files... works for now
    QTextStream inStream(&gff2);
    QTextStream outStream(&out);

    int mRNACount = 0;
    int infoCount = 0;
    clusterId = "no cluster";
    do {
        line = inStream.readLine();
        //qDebug() << "line = " << line << endl;

        if( ! line.startsWith("#") )
        {
            //divide line into major tokens- by the tab delim
           QStringList majorTokens = line.split("\t", QString::SkipEmptyParts);

           //get species, strain and contig from the first token
           //note- may not be able to always assume that format is species_strain_contig
           QStringList speciesStrainContig = majorTokens[0].split( "_", QString::SkipEmptyParts );
           QString species = speciesStrainContig[0];
           QString strain = speciesStrainContig[1];
           QString contig =  speciesStrainContig[2];

           //qDebug() << "    species = " << species << "   strain = " << strain << "   contig = " << contig << endl;

           int start = majorTokens[3].toInt();//start is forth token
           int stop = majorTokens[4].toInt();//stop if fifth
           QString strand = majorTokens[6]; //true;
           //if( majorTokens[6].contains("-"))//strand is sixth
               //posStrand = false;

           //NOTE:  only considering mRNA's- ignoring operons for now
           if( majorTokens[2].contains("mRNA") )
           {
               mRNACount++;
               QString id = ".";//all should have an id:  Species_Strain_Contig_G_N.N
               QString uniprot = "-";//not all will have uniprot id
               QString description = "-";//not all will have a description
               QString name = "-";
               QString perc_qry_cvrg = "-";
               QString perc_hit_cvrg = "-";
               QString perc_ident = "-";
               QString exp = "-";

               //get id
               if( majorTokens[8].contains("ID=") )
               {
                   QRegExp rx("ID=[^;]*;");//ID=any num characters execpt ; then ;
                   int pos = rx.indexIn( majorTokens[8]);
                   QStringList list = rx.capturedTexts();
                   for(int i = 0; i < list.size(); i++)
                   {
                       id = list[i].remove(".cdna;").remove("ID=");
                       //qDebug() << "------ id    " << id << endl;
                   }
               }

               //get uniprot
               if( majorTokens[8].contains("Note=") )
               {
                   QRegExp rx("Note=[^:]*:");//Note=any num characters execpt : then :
                   int pos = rx.indexIn( majorTokens[8]);
                   QStringList list = rx.capturedTexts();
                   for(int i = 0; i < list.size(); i++)
                   {
                       uniprot = list[i].remove("Note=").remove(":");
                       //qDebug() << "------ uniprot    " << uniprot << endl;
                   }
               }

               //get description
               if( majorTokens[8].contains("Note=") )
               {
                   //QRegExp rx("Note=[^=]*n=");//Note=any num characters then n=
                   QRegExp rx("Note=[^%=]*[%=]");//Note=any num characters then n=
                   int pos = rx.indexIn( majorTokens[8]);
                   QStringList list = rx.capturedTexts();
                   for(int i = 0; i < list.size(); i++)
                   {

                       //QRegExp rx2(":[^=]*n=");//take first regexp, apply new pattern  : any num char n=
                       QRegExp rx2(":[^%=]*[%=]");//take first regexp, apply new pattern  : any num char n=
                       int pos2 = rx2.indexIn( list[i]);
                       QStringList list2 = rx2.capturedTexts();
                       description = list2[0].remove(":").remove("n=").remove("(/%");
                       //qDebug() << "------ getting descr    " << description << endl;
                   }
               }

               //get name
               if( majorTokens[8].contains("RepID=") )
               {
                   QRegExp rx("RepID=[^(]*");//Note=any num characters then n=
                   int pos = rx.indexIn( majorTokens[8]);
                   QStringList list = rx.capturedTexts();
                   for(int i = 0; i < list.size(); i++)
                   {
                       name = list[i].remove("RepID=").remove(" ");//.remove("(");
                       //qDebug() << "------name    " << name << endl;
                   }
               }

               //get perc_qry_cvrg
               if( majorTokens[8].contains("/%qry_cvrg=") )
               {
                   QRegExp rx("/%qry_cvrg=[0-9]{1,3}");//Note=any num characters then n=
                   int pos = rx.indexIn( majorTokens[8]);
                   QStringList list = rx.capturedTexts();
                   for(int i = 0; i < list.size(); i++)
                   {
                       //perc_qry_cvrg = (list[i].remove("/%qry_cvrg=")).toInt();//.remove("(");
                       perc_qry_cvrg = (list[i].remove("/%qry_cvrg=").remove(" "));//.toInt();//.remove("(");
                       //qDebug() << "------perc_qry_cvrg    " << perc_qry_cvrg << endl; //<< list[i] << endl;//
                   }
               }

               //get perc_hit_cvrg
               if( majorTokens[8].contains("/%hit_cvrg=") )
               {
                   QRegExp rx("/%hit_cvrg=[0-9]{1,3}");//Note=any num characters then n=
                   int pos = rx.indexIn( majorTokens[8]);
                   QStringList list = rx.capturedTexts();
                   for(int i = 0; i < list.size(); i++)
                   {
                       //perc_qry_cvrg = (list[i].remove("/%qry_cvrg=")).toInt();//.remove("(");
                       perc_hit_cvrg = (list[i].remove("/%hit_cvrg=").remove(" "));//.toInt();//.remove("(");
                       //qDebug() << "------perc_hit_cvrg    " << perc_hit_cvrg << endl; //<< list[i] << endl;//
                   }
               }

               //get perc_ident
               if( majorTokens[8].contains("/%ident=") )
               {
                   QRegExp rx("/%ident=[0-9]{1,3}");//Note=any num characters then n=
                   int pos = rx.indexIn( majorTokens[8]);
                   QStringList list = rx.capturedTexts();
                   for(int i = 0; i < list.size(); i++)
                   {
                       //perc_qry_cvrg = (list[i].remove("/%qry_cvrg=")).toInt();//.remove("(");
                       perc_ident = (list[i].remove("/%ident=").remove(" "));//.toInt();//.remove("(");
                       //qDebug() << "------perc_ident    " << perc_ident << endl; //<< list[i] << endl;//
                   }
               }

               //get exp
               if( majorTokens[8].contains("/exp=") )
               {
                   QRegExp rx("/exp=[^//]* ");//Note=any num characters then n=
                   int pos = rx.indexIn( majorTokens[8]);
                   QStringList list = rx.capturedTexts();
                   for(int i = 0; i < list.size(); i++)
                   {
                       exp = (list[i].remove("/exp=").remove(" "));//.toInt();//.remove("(");
                       //qDebug() << "------exp    " << exp << endl; //<< list[i] << endl;//
                   }
               }

               QList<QString> list = geneIdToClusterHT.values( id );
               if( list.size() >= 1 )
                 clusterId = list[0]; //big assumption here that something will be found
               else
                   qDebug() << "LOOKUP FAILED " <<endl;

               //make sure something is output
               if( uniprot.size() < 1 )
                    uniprot = "-";//not all will have uniprot id
               if( description.size() < 1 )
                    description = "-";//not all will have a description
               if( name.size() < 1 )
                    name = "-";
               if( perc_qry_cvrg.size() < 1 )
                    perc_qry_cvrg = "na";
               if( perc_hit_cvrg.size() < 1 )
                    perc_hit_cvrg = "na";
               if( perc_ident.size() < 1 )
                    perc_ident = "na";
               if( exp.size() < 1 )
                    exp = "na";

               outStream << species << "\t" << strain << "\t" << contig << "\t" << id << "\t" << start << "\t" << stop << "\t" << strand
                            << "\t" << clusterId << "\t" << uniprot << "\t" << description << "\t" << name << "\t" << perc_qry_cvrg << "\t" << perc_hit_cvrg
                               << "\t" << perc_ident << "\t" << exp << endl;
               clusterId = "no cluster";

           }//end mRNA

        }//end line

        qDebug() << "mRNA count = " << mRNACount << "  infoCount =  " << infoCount << endl;
    } while (!inStream.atEnd() );

    emit( trackProgress(80) );

    gff2.close();
    out.close();

    return true;
}
